package com.inspur.security.cbb3.kms.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Predicates;
import com.inspur.security.cbb3.kms.config.xss.XssFilter;
import com.inspur.security.cbb3.kms.mkek.Mkek;
import com.inspur.security.cbb3.kms.mkek.MkekHsm;
import com.inspur.security.cbb3.kms.mkek.MkekSoftware;
import org.apache.commons.lang3.StringUtils;
import org.jasypt.util.text.BasicTextEncryptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.DispatcherType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 一些配置类
 *
 * @author lijunchang
 */
@Configuration
@EnableSwagger2
public class WebConfig {

    @Value("${jasypt.encryptor.password}")
    private String sKey;

    @Value("${xss.enabled}")
    private String enabled;

    @Value("${xss.excludes}")
    private String excludes;

    @Value("${xss.urlPatterns}")
    private String urlPatterns;

    /**
     * 装载BCrypt密码编码器
     *
     * @return 密码解析器
     */
    @Bean
    public BasicTextEncryptor basicTextEncryptor() {
        BasicTextEncryptor e = new BasicTextEncryptor();
        e.setPassword(sKey);
        return e;
    }

    /**
     * ==================SWAGGER===============================
     */
    private Contact contact = new Contact("安全技术部", "http://www.inspur.com/", "lijunchang@inspur.com");

    @Bean
    public Docket createRestApi() {
        //添加header参数
        ParameterBuilder ticketPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<>();
        ticketPar.name("Authorization").description("用户口令")
                .modelRef(new ModelRef("string")).parameterType("header")
                .required(false).pattern("/sys/**").build();
        //header中的ticket参数非必填，传空也可以
        //根据每个方法名也知道当前方法在设置什么参数
        pars.add(ticketPar.build());

        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build()
                .globalOperationParameters(pars)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("统一签名平台接口 v1.0")
                .description("统一签名平台接口 v1.0")
                .contact(contact)
                .version("1.0")
                .build();
    }

    //REDIS
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * xss过滤拦截器
     */
    @Bean
    public FilterRegistrationBean xssFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
        registrationBean.setFilter(new XssFilter());
        registrationBean.addUrlPatterns(StringUtils.split(urlPatterns, ","));
        registrationBean.setName("XssFilter");
        registrationBean.setOrder(9999);
        Map<String, String> initParameters = new HashMap<>(2);
        initParameters.put("excludes", excludes);
        initParameters.put("enabled", enabled);
        registrationBean.setInitParameters(initParameters);
        return registrationBean;
    }

    @Value("${signweb.plugin.name}")
    private String pluginName = "HSM";

    @Value("${signweb.mkek.keyContent}")
    private String key = "";

    @Value("${signweb.mkek.iv}")
    private String iv = "";

    @Value("${signweb.hsm.ip}")
    private String ip = "";

    @Value("${signweb.hsm.port}")
    private String port = "";

    private static final String PLUGIN_NAME_DEF = "HSM";

    @Bean
    public Mkek getMkek() {
        if (PLUGIN_NAME_DEF.equals(pluginName)) {
            return new MkekHsm(ip, port);
        }
        return new MkekSoftware(key, iv);
    }
}
